package com.yupi.yu_picture.manager.auth.model;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReflectUtil;
import com.yupi.yu_picture.exception.BusinessException;
import com.yupi.yu_picture.exception.ErrorCode;
import com.yupi.yu_picture.model.entity.SpaceUser;
import com.yupi.yu_picture.model.entity.Picture;
import com.yupi.yu_picture.model.entity.Space;

import cn.dev33.satoken.stp.StpInterface;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.Header;
import cn.hutool.json.JSONUtil;
import com.yupi.yu_picture.manager.auth.model.StpKit.java.StpKit;
import com.yupi.yu_picture.model.entity.User;
import com.yupi.yu_picture.model.enums.SpaceRoleEnum;
import com.yupi.yu_picture.model.enums.SpaceTypeEnum;
import com.yupi.yu_picture.service.PictureService;
import com.yupi.yu_picture.service.SpaceService;
import com.yupi.yu_picture.service.SpaceUserService;
import com.yupi.yu_picture.service.UserService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

import static com.yupi.yu_picture.constant.UserConstant.USER_LOGIN_STATE;

/**
 * 自定义权限加载接口实现类
 */
@Component    // 保证此类被 SpringBoot 扫描，完成 Sa-Token 的自定义权限验证扩展
public class StpInterfaceImpl implements StpInterface {

    @Resource
    SpaceUserAuthManager spaceUserAuthManager;

    @Resource
    SpaceUserService spaceUserService;
    @Resource
    UserService userService;
    @Resource
    SpaceService spaceService;
    @Resource
    PictureService pictureService;

    /**
     * 返回一个账号所拥有的权限码集合 
     */
    @Override
    public List<String> getPermissionList(Object loginId, String loginType) {
        // 判断登陆类型，只对space类型进行权限校验
        if(!loginType.equals(StpKit.SPACE_TYPE)){
            return new ArrayList<>();
        }
        //管理员权限，权限校验通过返回该权限集合，表示权限校验通过
        List<String> ADMIN_PERMISSIONS = spaceUserAuthManager.getPermissionByRole(SpaceRoleEnum.ADMIN.getValue());
        //获取上下文对象
        SpaceUserAuthContext authContext = getAuthContextByRequest();
        //如果所有字段都为空，表示查询公共图库，可以通过
        //TODO
        if (isAllFieldsNull(authContext)){
            return ADMIN_PERMISSIONS;
        }

        //获取userId
        User loginUser  = (User)StpKit.SPACE.getSessionByLoginId(loginId).get(USER_LOGIN_STATE);
        if (loginUser==null){
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR,"用户未登录");
        }
        Long userId = loginUser.getId();
        //优先从上下文中获取space user对象，可以直接根据用户角色得到所有权限
        SpaceUser spaceUser = authContext.getSpaceUser();
        if (spaceUser!=null){
            return spaceUserAuthManager.getPermissionByRole(spaceUser.getSpaceRole());
        }
        //如果有spaceuserId，必然是团队空间，得到space user对象，根据角色得到权限
        Long spaceUserId = authContext.getSpaceUserId();
        if (spaceUserId!=null){
            spaceUser = spaceUserService.getById(spaceUserId);
            if (spaceUser==null){
                throw new BusinessException(ErrorCode.NOT_FOUND_ERROR,"未找到空间用户信息");
            }
            //得到当前用户对应的spaceuser，防止直接通过输入loginid来访问
            SpaceUser loginSpaceUser = spaceUserService.lambdaQuery()
                    .eq(SpaceUser::getId, spaceUserId)
                    .eq(SpaceUser::getUserId, loginUser.getId())
                    .one();
            if (loginSpaceUser==null){
                return new ArrayList<>();
            }
            //这里会导致管理员在私有空间没有权限，可以再查一次库处理
            return spaceUserAuthManager.getPermissionByRole(loginSpaceUser.getSpaceRole());

        }
        //如果没有spaceuserid，尝试通过spaceId或picturId获取space对象并处理
        Long spaceId = authContext.getSpaceId();
        if (spaceId==null){
            Long pictureId = authContext.getPictureId();
            if (pictureId==null){
                return ADMIN_PERMISSIONS;
            }
            Picture picture = pictureService.lambdaQuery()
                    .eq(Picture::getId, pictureId)
                    .select(Picture::getId, Picture::getUserId, Picture::getSpaceId)
                    .one();
            if (picture==null){
                throw new BusinessException(ErrorCode.NOT_FOUND_ERROR,"未找到图片信息");
            }
            //对于图片，仅管理员和创建者可以删改，其余人只有查看的权限
            spaceId=picture.getSpaceId();
            if (spaceId==null){
                if (picture.getUserId().equals(userId)||userService.isAdmin(loginUser)){
                    return ADMIN_PERMISSIONS;
                }else{
                    return Collections.singletonList(SpaceUserPermissionConstant.PICTURE_VIEW);
                }
            }
        }
        Space space = spaceService.getById(spaceId);
        if (space==null){
            throw new BusinessException(ErrorCode.NOT_FOUND_ERROR,"未找到空间信息");
        }
        //根据space类型判断权限
        if(space.getSpaceType().equals(SpaceTypeEnum.PRIVATE.getValue())){
            if (space.getUserId().equals(userId)||userService.isAdmin(loginUser)){
                return ADMIN_PERMISSIONS;
            }else{
                return new ArrayList<>();
            }
        }else{
            spaceUser = spaceUserService.lambdaQuery()
                    .eq(SpaceUser::getSpaceId, spaceId)
                    .eq(SpaceUser::getUserId, userId)
                    .one();
            if (spaceUser==null){
                return new ArrayList<>();
            }
            return spaceUserAuthManager.getPermissionByRole(spaceUser.getSpaceRole());
        }

    }

    //判断某个类所有字段是否为空
    private boolean isAllFieldsNull(Object object) {
         if(object==null){
             return true;
         }
         //获取所有字段并判断是否所有字段为空
         return Arrays.stream(ReflectUtil.getFields(object.getClass()))
                 .map(field -> ReflectUtil.getFieldValue(object,field))
                 .allMatch(Objects::isNull);


    }

    /**
     * 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)
     */
    @Override
    public List<String> getRoleList(Object loginId, String loginType) {
        // 本 list 仅做模拟，实际项目中要根据具体业务逻辑来查询角色
        List<String> list = new ArrayList<String>();    
        list.add("admin");
        list.add("super-admin");
        return list;
    }


    @Value("${server.servlet.context-path}")
    private String contextPath;

    private SpaceUserAuthContext getAuthContextByRequest(){
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        String contentType = request.getHeader(Header.CONTENT_TYPE.getValue());
        SpaceUserAuthContext authRequest;
        if (ContentType.JSON.getValue().equals(contentType)){
            String body = ServletUtil.getBody(request);
            authRequest = JSONUtil.toBean(body, SpaceUserAuthContext.class);
        }else{
            Map<String, String> paramMap = ServletUtil.getParamMap(request);
            authRequest= BeanUtil.toBean(paramMap,SpaceUserAuthContext.class);
        }
        //根据请求路径区分id字段的含义
        Long id = authRequest.getId();
        if (ObjUtil.isNotNull(id)){
            String requestURI = request.getRequestURI();
            String partUri = requestURI.replace(contextPath + "/", "");
            String moduleName = StrUtil.subBefore(partUri, "/", false);
            switch(moduleName){
                case "picture":
                    authRequest.setPictureId(id);
                    break;
                case "space":
                    authRequest.setSpaceId(id);
                    break;
                default:

            }

        }
        return authRequest;


    }
}
